<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <title>snake</title>
  <script src="https://cdn.jsdelivr.net/npm/vue"></script>
  <style>
    td {
      border: 1px solid #666;
      width: 10px;
      height: 10px;
    }

    table {
      border-collapse: collapse;
    }

    .active {
      background: #f60
    }
  </style>
</head>

<body>
  <div id="snake">
    <table>
      <tr v-for="(col,y) in cols">
        <td v-for="(row,x) in rows" :class="body(x,y)||showfood(x,y)?'active':''"></td>
      </tr>
    </table>
    <button @click="start()">开始</button>
  </div>
  <script>
    let timer = '' //定时器
    new Vue({
      el: '#snake',
      data() {
        return {
          rows: '', //横框
          cols: '', //竖框
          position: [
            [0, 0],
            [1, 0],
            [2, 0],
            [3, 0]
          ], //蛇的初始位置
          direction: 1, //方向
          food: [], //食物的位置
          game: false, //游戏是否结束
          falg: true
        }
      },
      mounted() {
        this.keyboard()
        this.background()
        this.creatfood()
      },
      methods: {
        background() { //生成横框和竖框的函数
          this.rows = Array(30)
          this.cols = Array(30)
        },
        keyboard() { //键盘事件
          let _this = this;
          document.onkeydown = function (e) {
            if (e.keyCode === 37) {
              _this.change(-1)
            } else if (e.keyCode === 38) {
              _this.change(-2)
            } else if (e.keyCode === 39) {
              _this.change(1)
            } else {
              _this.change(2)
            }
          }
        },
        creatfood() { //创造食物
          this.food[0] = Math.floor(Math.random() * 30)
          this.food[1] = Math.floor(Math.random() * 30)
        },
        showfood(x, y) { //显示食物
          if (this.food[0] === x && this.food[1] === y) {
            return true
          }
        },
        body(x, y) { //显示身体
          let X, Y
          for (i = 0; i < this.position.length; i++) {
            if (this.position[i][0] === x && this.position[i][1] === y) {
              return true
            }
          }
        },
        start() { //开始按钮
          this.game = true
          if (timer) clearInterval(timer)
          if (this.game) {
            timer = setInterval(() => this.autorun(), 300)
          }
        },
        change(dir) { //改变方向
          if (Math.abs(dir) === Math.abs(this.direction)) { //如果方向相同或者相反，不做任何操作
            return
          } else {
            this.direction = dir //否则改变方向
          }
        },
        autorun() {
          let direction = this.direction //目前方向
          let headX, headY
          headX = this.position[this.position.length - 1][0] //复制蛇头的X坐标
          headY = this.position[this.position.length - 1][1] //复制蛇头的Y坐标
          if (direction === 1 || direction === -1) { //如果方向是在左右跑动     						
            direction > 0 ? headX++ : headX-- //往右跑X坐标+1，往左跑X坐标-1 										
          } else {
            direction > 0 ? headY++ : headY-- //如果方向是在上下跑动，Y坐标做对应处理
          } //此时蛇头的下一个坐标位置就是[headX,headY]，接下来就可以判断是否结束游戏，如果结束了，蛇头就没必要添加了
          if (headX < 0 || headX > 29 || headY < 0 || headY > 29 || this.body(headX,
              headY)) { //当蛇头下一个位置出了边界或者这个位置是符合身体函数（即蛇头撞上了身体）
            this.game = false
            alert('Game Over')
            clearInterval(timer)
            this.position = [
              [0, 0],
              [1, 0],
              [2, 0],
              [3, 0]
            ]
            this.creatfood()
            this.direction = 1
          } else { //如果蛇头下一个位置是符合规则的						
            this.position.push([headX, headY]) //将下一个位置添加进数组，头部长一节
            if (headX !== this.food[0] || headY !== this.food[1]) { //如果下一个头部位置不是食物的位置，即吃食物开始						
              this.position.shift() //我们将尾部去掉，一长一短实现了蛇的走动
            } else { //如果下一个头部位置是食物
              this.creatfood() //不去除尾部，再次创建食物（这里有个小bug，随机的食物有几率与身体重合）
            }
          }
        }
      }
    })
  </script>
</body>

</html>